﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Sublimation.Behaviours
{
    public class UnitCohesionBehaviour : Behaviour
    {
        protected WorldProperties worldProperties;
        protected Unit owner;
        protected float weight;
        public float getWeight() { return this.weight; }
        protected float separationDistance;

        public UnitCohesionBehaviour(WorldProperties worldProperties, Unit owner, float weight, float separationDistance)
        {
            this.worldProperties = worldProperties;
            this.owner = owner;
            this.weight = weight;
            this.separationDistance = separationDistance;
        }

        public Vector2 RunBehaviour()
        {
            // move closer to friendly units
            Vector2 result = Vector2.Zero;

            int unitsInSightRangeCount = 0;

            foreach (EnemyUnit unit in worldProperties.Enemies)
            {
                if (Object.ReferenceEquals(owner, unit)) continue;
                if (Vector2.Distance(unit.Position, owner.Position) <= owner.AISightRange)
                {
                    result += EvaluateAgainst(unit);
                    unitsInSightRangeCount++;
                }
            }
            foreach (Player player in worldProperties.Players)
            {
                foreach (FriendlyUnit unit in player.Units)
                {
                    if (Object.ReferenceEquals(owner, unit)) continue;
                    if (Vector2.Distance(unit.Position, owner.Position) <= owner.AISightRange)
                    {
                        result += EvaluateAgainst(unit);
                        unitsInSightRangeCount++;
                    }
                }
            }

            if (unitsInSightRangeCount > 0) result /= unitsInSightRangeCount;

            return result * weight;
        }

        protected Vector2 EvaluateAgainst(Unit other)
        {
            // if the units are visible, friendly and not too close lets move closer
            if ((other is FriendlyUnit && owner is FriendlyUnit) || (other is EnemyUnit && owner is EnemyUnit))
            {
                // if they arent already too close
                if (Vector2.Distance(other.Position, owner.Position) > separationDistance)
                {
                    // move in the direction of the other unit, more the further away it is
                    Vector2 result = Vector2.Normalize(other.Position - owner.Position) *
                        (float)Math.Pow((double)
                            (Vector2.Distance(other.Position, owner.Position) - separationDistance) / (owner.AISightRange - separationDistance)
                            , 2);

                    // clamp to max speed
                    if (result.Length() > owner.MaxSpeed) return Vector2.Normalize(result) * owner.MaxSpeed;
                    return result;
                }
            }
            return Vector2.Zero;
        }
    }
}
